package com.example.waterdispenserm2.mo.copy;



import android.util.Log;

import com.aill.androidserialport.SerialPort;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class CopyInductionCookerSlave {
    private static final String TAG = "InductionCookerSlave";
    private SerialPort mSerialPort;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    private boolean isRunning = false;
    private Thread receiveThread;
    private Thread sendThread;
    private OnHostDataReceivedListener dataListener;
    private OnLogUpdateListener logListener;

    // 协议常量（对应文档定义）
    private static final int IDLE_LEVEL = 1; // 空闲电平：高电平{insert\_element\_0\_}
    private static final int GUIDE_CODE_DURATION = 2; // 引导码时长：2ms{insert\_element\_1\_}
    private static final int ONE_CODE_HIGH = 500; // 1码高电平：500us{insert\_element\_2\_}
    private static final int ONE_CODE_LOW = 250; // 1码低电平：250us{insert\_element\_3\_}
    private static final int ZERO_CODE_HIGH = 125; // 0码高电平：125us{insert\_element\_4\_}
    private static final int ZERO_CODE_LOW = 625; // 0码低电平：625us{insert\_element\_5\_}
    private static final int REPLY_DELAY = 4; // 接收后回复延时：4ms{insert\_element\_6\_}

    // 按键键值（对应文档定义）
    public static final byte KEY_NONE = 0x00;
    public static final byte KEY_POWER_VOLTAGE = 0x01;
    public static final byte KEY_TIMER = 0x02;
    public static final byte KEY_MINUS = 0x03;
    public static final byte KEY_PLUS = 0x04;
    public static final byte KEY_FUNCTION = 0x05;
    public static final byte KEY_START = 0x06; // {insert\_element\_7\_}

    private byte currentKey = KEY_NONE;

    // 日志更新回调接口
    public interface OnLogUpdateListener {
        void onLogUpdated(String log);
    }

    // 主机数据接收回调接口
    public interface OnHostDataReceivedListener {
        void onHostDataReceived(byte[] displayData);
    }

    public void setOnHostDataReceivedListener(OnHostDataReceivedListener listener) {
        this.dataListener = listener;
    }

    public void setOnLogUpdateListener(OnLogUpdateListener listener) {
        this.logListener = listener;
    }

    /**
     * 初始化串口通信
     */
    public boolean init(String devicePath, int baudRate) {
        try {
            mSerialPort = new SerialPort(new File(devicePath), baudRate, 0);
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();
            isRunning = true;
            startReceiveThread();
            addLog("串口初始化成功，设备路径：" + devicePath);
            return true;
        } catch (IOException e) {
            addLog("串口初始化失败：" + e.getMessage());
            return false;
        }
    }

    /**
     * 启动接收线程
     */
    private void startReceiveThread() {
        receiveThread = new Thread(() -> {
            byte[] buffer = new byte[1024];
            int length;
            while (isRunning) {
                try {
                    if ((length = mInputStream.read(buffer)) > 0) {
                        byte[] hostData = new byte[length];
                        System.arraycopy(buffer, 0, hostData, 0, length);
                        addLog("收到主机数据：" + bytesToHex(hostData));

                        if (verifyHostFrame(hostData)) {
                            addLog("主机数据校验通过，等待" + REPLY_DELAY + "ms后回复");
                            Thread.sleep(REPLY_DELAY);
                            sendSlaveData(currentKey);
                        } else {
                            addLog("主机数据校验失败");
                        }
                    }
                } catch (Exception e) {
                    addLog("接收线程异常：" + e.getMessage());
                    break;
                }
            }
        });
        receiveThread.start();
    }

    /**
     * 验证主机帧（文档帧结构：引导码+1byte识别码+5byte显示码+1byte校验码）
     */
    private boolean verifyHostFrame(byte[] frame) {
        if (frame.length != 7) { // 总长度应为7字节（不含引导码）{insert\_element\_8\_}
            addLog("主机帧长度错误，实际：" + frame.length + "，预期：7");
            return false;
        }
        if (frame[0] != 0xA5) { // 识别码固定为0xA5{insert\_element\_9\_}
            addLog("识别码错误，实际：0x" + Integer.toHexString(frame[0] & 0xFF) + "，预期：0xA5");
            return false;
        }
        // 和校验：识别码+显示码之和的低8位{insert\_element\_10\_}
        byte checksum = 0;
        for (int i = 0; i < 6; i++) {
            checksum += frame[i];
        }
        if (checksum != frame[6]) {
            addLog("校验码错误，计算：0x" + Integer.toHexString(checksum & 0xFF) + "，实际：0x" + Integer.toHexString(frame[6] & 0xFF));
            return false;
        }
        // 解析显示码并回调
        byte[] displayData = new byte[5];
        System.arraycopy(frame, 1, displayData, 0, 5); // 提取5字节显示码{insert\_element\_11\_}
        if (dataListener != null) {
            dataListener.onHostDataReceived(displayData);
        }
        return true;
    }

    /**
     * 发送从机数据（文档帧结构：引导码+1byte数据码+1byte校验码）
     */
    private void sendSlaveData(byte key) {
        byte[] data = new byte[2];
        data[0] = key; // 数据码：按键键值{insert\_element\_12\_}
        data[1] = (byte) (~key); // 校验码：数据码取反{insert\_element\_13\_}

        sendThread = new Thread(() -> {
            try {
                addLog("开始发送从机数据：键值0x" + Integer.toHexString(key & 0xFF) + "，校验码0x" + Integer.toHexString(data[1] & 0xFF));

                // 发送引导码：2ms低电平{insert\_element\_14\_}
                setLineLevel(0);
                Thread.sleep(GUIDE_CODE_DURATION);

                // 发送数据码和校验码（每bit按0/1码时序）
                for (byte b : data) {
                    for (int i = 7; i >= 0; i--) {
                        int bit = (b >> i) & 0x01;
                        if (bit == 1) {
                            // 1码：500us高+250us低{insert\_element\_15\_}
                            setLineLevel(1);
                            Thread.sleep(0, ONE_CODE_HIGH * 1000);
                            setLineLevel(0);
                            Thread.sleep(0, ONE_CODE_LOW * 1000);
                        } else {
                            // 0码：125us高+625us低{insert\_element\_16\_}
                            setLineLevel(1);
                            Thread.sleep(0, ZERO_CODE_HIGH * 1000);
                            setLineLevel(0);
                            Thread.sleep(0, ZERO_CODE_LOW * 1000);
                        }
                    }
                }

                // 恢复空闲电平（高电平）{insert\_element\_17\_}
                setLineLevel(1);
                addLog("从机数据发送完成");
            } catch (Exception e) {
                addLog("发送线程异常：" + e.getMessage());
            }
        });
        sendThread.start();
    }

    /**
     * 控制通信线电平
     */
    private void setLineLevel(int level) {
        try {
            mOutputStream.write(level == 1 ? 0xFF : 0x00);
            mOutputStream.flush();
        } catch (IOException e) {
            addLog("设置电平失败：" + e.getMessage());
        }
    }

    /**
     * 更新按键状态
     */
    public void updateKeyStatus(byte key) {
        this.currentKey = key;
        addLog("按键状态更新：0x" + Integer.toHexString(key & 0xFF) + "（" + getKeyName(key) + "）");
    }

    /**
     * 获取按键名称（对应文档定义）
     */
    private String getKeyName(byte key) {
        switch (key) {
            case 0x01: return "电量/电压";
            case 0x02: return "定时/预约";
            case 0x03: return "减";
            case 0x04: return "加";
            case 0x05: return "功能";
            case 0x06: return "启动";
            default: return "无按键";
        } // {insert\_element\_18\_}
    }

    /**
     * 添加日志
     */
    private void addLog(String log) {
        String time = android.text.format.DateFormat.format("HH:mm:ss", new java.util.Date()).toString();
        String fullLog = "[" + time + "] " + log + "\n";
        if (logListener != null) {
            logListener.onLogUpdated(fullLog);
        }
        Log.d(TAG, log);
    }

    /**
     * 关闭资源
     */
    public void close() {
        isRunning = false;
        if (receiveThread != null) receiveThread.interrupt();
        if (sendThread != null) sendThread.interrupt();
        if (mSerialPort != null) mSerialPort.close();
        addLog("串口已关闭");
    }

    /**
     * 字节数组转十六进制
     */
    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b));
        }
        return sb.toString().trim();
    }
}


